package org.keyroy.map_editor.map;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import javax.imageio.ImageIO;

import org.keyroy.map_editor.map.m.Building;
import org.keyroy.map_editor.map.m.BuildingMark;
import org.keyroy.tag.Tag;
import org.keyroy.tag.XmlSupport;

public class MapResource implements XmlSupport {
	public Hashtable<Integer, String> floorTable = new Hashtable<Integer, String>();
	public Hashtable<Integer, Building> buildingTable = new Hashtable<Integer, Building>();

	private BufferedImage[] floorCache = new BufferedImage[1024];
	private Building[] buildingCache = new Building[1024];

	private SourceListener sourceListener;

	public List<Integer> unMoveableFloorID = new ArrayList<Integer>();
	public int fid = 1;
	public int bid = 1;

	private final int getFloorID() {
		int ID = fid;
		fid++;
		return ID;
	}

	private final int getBuildingID() {
		int ID = bid;
		bid++;
		return ID;
	}

	// =============================================

	public final void addFloor(File file, boolean callListener) {
		if (file.isFile() && floorTable.contains(file.getAbsolutePath()) == false) {
			try {
				ImageIO.read(new FileInputStream(file));
				int ID = getFloorID();
				floorTable.put(ID, file.getAbsolutePath());
				if (callListener) {
					sourceListener.onFloorImageAt(ID, file);
				}
			} catch (Exception e) {
			}

		} else if (file.isDirectory()) {
			File[] files = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				addFloor(files[i], false);
			}
			sourceListener.onFlushFloorImage();
		}
	}

	public final void deleteFloor(int id) {
		floorTable.remove(id);
		floorCache[id] = null;
	}

	// ********************************************************************************

	public final void addBuildingFloor(Map map, File file, boolean flushPanel) {
		if (file.isFile() && buildingTable.contains(file.getAbsolutePath()) == false) {
			int ID = getBuildingID();
			try {
				BufferedImage bufferedImage = ImageIO.read(file);
				buildingTable.put(ID, new Building(ID, file, map, bufferedImage));
				if (flushPanel) {
					sourceListener.onFlushBuildingImage();
				}
			} catch (Exception e) {
			}

		} else if (file.isDirectory()) {
			File[] files = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				addBuildingFloor(map, files[i], false);
			}
			sourceListener.onFlushBuildingImage();
		}
	}

	public final void deleteBuilding(int id) {
		buildingTable.remove(id);
		buildingCache[id] = null;
	}

	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	public final BufferedImage loadFloor(int i) {
		if (i == 0) {
			return null;
		} else {
			try {
				if (i >= floorCache.length) {
					BufferedImage[] newArray = new BufferedImage[floorCache.length * 2];
					System.arraycopy(floorCache, 0, newArray, 0, floorCache.length);
					floorCache = newArray;
				}
				BufferedImage image = floorCache[i];
				if (image == null) {
					String path = floorTable.get(i);
					if (path == null) {
						return null;
					} else {
						BufferedImage bufferedImage = ImageIO.read(new File(floorTable.get(i)));
						floorCache[i] = bufferedImage;
						return bufferedImage;
					}

				} else {
					return image;
				}

			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("ID = " + i);
			}
		}

		return null;
	}

	public final Building loadBuliding(int i, Map map) {
		try {
			if (i >= buildingCache.length) {
				Building[] newArray = new Building[buildingCache.length * 2];
				System.arraycopy(buildingCache, 0, newArray, 0, buildingCache.length);
				buildingCache = newArray;
			}
			if (buildingCache[i] == null) {
				Building building = buildingTable.get(i);
				if (building != null) {
					if (building.bufferedImage == null) {
						building.init(map, ImageIO.read(building.file));
					}

					buildingCache[i] = building;
				}
			}
			return buildingCache[i].getCopy();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public final Building loadBuliding(BuildingMark buildingMark, Map map) {
		return loadBuliding(buildingMark.sID, map);
	}

	// =============================================================================
	public BufferedImage load(File file) {
		try {
			BufferedImage bufferedImage = ImageIO.read(file);
			return bufferedImage;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public final int size() {
		return floorTable.size() - 1;
	}

	public void setSourceListener(SourceListener sourceListener) {
		this.sourceListener = sourceListener;
	}

	@Override
	public String getTagName() {
		return "mr";
	}

	public final void printFloors() {
		Enumeration<Integer> keys = floorTable.keys();
		Enumeration<String> elements = floorTable.elements();
		while (elements.hasMoreElements()) {
			int key = keys.nextElement();
			String string = (String) elements.nextElement();

			System.out.println("key = " + key + "    value = " + string);
		}
	}

	@Override
	public void initObj(Tag tag) {

		List<Tag> tags = tag.getChildTagArray("fi");
		for (int i = 0; i < tags.size(); i++) {
			Tag cTag = tags.get(i);
			int key = cTag.getParameterIntValue("id");
			String value = cTag.getParameterValue("img");
			floorTable.put(key, value);
			fid = Math.max(fid, key) + 1;
		}

		List<XmlSupport> supports = tag.getChildObjectArray(Building.class);
		for (int i = 0; i < supports.size(); i++) {
			Building building = (Building) supports.get(i);
			buildingTable.put(building.ID, building);
		}

	}

	@Override
	public void initTag(Tag tag) {

		Enumeration<Integer> keys = floorTable.keys();
		Enumeration<String> elements = floorTable.elements();
		while (elements.hasMoreElements()) {
			int key = keys.nextElement();
			String string = (String) elements.nextElement();
			Tag cTag = new Tag();
			cTag.setName("fi");
			cTag.addParameter("id", key);
			cTag.addParameter("img", string);
			tag.addChild(cTag);
		}

		keys = buildingTable.keys();
		tag.addChild(buildingTable.elements());
	}

	public interface SourceListener {
		public void onFloorImageAt(int ID, File file);

		public void onFlushFloorImage();

		public void onBuildingImageAt(int ID, File file);

		public void onFlushBuildingImage();
	}

}
